#include "stdafx.h"
#include "qstring.h"

//in honor of Paul DiLascia


using namespace micro::utils;



QString::QString()
{
    // Clear pointers.
    m_pszString = nullptr;

}

// Copy constructor.
QString::QString( const QString & csSource )
{
    // Set the source buffer in this object.
    m_pszString = csSource.m_pszString;


    // If the source was valid we add a reference to it.
    if ( m_pszString ) GetBuf()->AddRef();
}




// Construct a string of "nRepeat" "ch" characters.
QString::QString( TCHAR ch, int nRepeat /* = 1 */ )
{
    ASSERT( nRepeat >= 1 );    // nRepeat must be 1 or higher.
    ASSERT( ch != _T( '\0' ) ); // We do not set to nil's.

    // Clear pointers.
    m_pszString = nullptr;


    // Allocate the required buffer.
    AllocateBuffer( nRepeat );

#ifdef _UNICODE

    // On Unicode builds we copy the characters one by
    // one.
    for ( int i = 0; i < nRepeat; i++ )
        m_pszString[ i ] = ch;

#else
    // Otherwise we do a simple memset on the
    // buffer.
    memset( m_pszString, ch, nRepeat );
#endif
}


// Construct a string of the input string.
QString::QString( LPCTSTR pszSource, int nChars /* = -1 */ )
{
    ASSERT( pszSource ); // A valid string is required.

    // Clear pointers.
    m_pszString   = nullptr;


    // If the hi-order word of "pszSource" is 0
    // we load the string from the resources.
    if ( pszSource && HIWORD( pszSource ) == 0 )
    {
        // Load the string.
        LoadString( LOWORD( pszSource ) );
        return;
    }

    // Allocate a new buffer if necessary.
    int len = ( nChars == -1 ? ( int )_tcslen( pszSource ) : nChars );

    AllocateBuffer( len  );

    // Copy the string.
    if ( nChars == -1 )
        _tcscpy( m_pszString, pszSource );
    else
    {
        memcpy( m_pszString, pszSource, nChars * sizeof( TCHAR ) );
        m_pszString[ nChars ] = _T( '\0' );
    }
}

#ifndef _UNICODE
// Constructor. Sets the contents to the string pointed
// to by the wide character string "pszSource".
QString::QString( LPCWSTR pszSource, int nChars /* = -1 */ )
{
    ASSERT( pszSource );	// A valid string is required.

    // Clear pointers.
    m_pszString   = nullptr;
    m_pszConverted = nullptr;


    // Allocate a new buffer if necessary.
    int nLength = nChars == -1 ? ( int )wcslen( pszSource ) : nChars;
    AllocateBuffer( nLength );

    // Copy the string.
    wcstombs( m_pszString, pszSource, nLength * sizeof( TCHAR ) );
}
#else
// Constructor. Sets the contents to the string pointed
// to by the character string "pszSource".
QString::QString( LPCSTR pszSource, int nChars /* = -1 */ )
{
    ASSERT( pszSource );	// A valid string is required.

    // Clear pointers.
    m_pszString   = nullptr;
    //m_pszConverted = nullptr;


    // Allocate a new buffer if necessary.
    int nLength = ( int )( nChars == -1 ? strlen( pszSource ) : nChars );
    AllocateBuffer( nLength );

    // Copy the string.
    mbstowcs( m_pszString, pszSource, nLength );
}
#endif // _UNICODE

// Destructor. Releases the string buffer.
QString::~QString()
{
    // Release buffer.
    //m_pszString;
    Release();
}

// Empty the string contents.
void QString::Empty()
{
    // Do not modify referenced data!
    CopyBeforeWrite();

    // Do we have a string?
    if ( m_pszString )
        GetBuf()->SetLength( 0 );
}

// Setup string length.
void QString::SetStringLength( int nLength )
{
    // QString buffer present?
    if ( m_pszString && GetBuf()->GetLength() != nLength )
    {
        // Do not modify referenced data!
        CopyBeforeWrite();

        // Setup new string length.
        GetBuf()->SetLength( nLength );
    }
}



// Equality test with another QString object
// to compare with.
bool QString::IsEqual( const QString & csSource ) const
{
    // Compare the two strings
    if ( ( &csSource == this ) || ( m_pszString && csSource.m_pszString && _tcscmp( m_pszString, csSource.m_pszString ) == 0 ) )
        return true;

    return false;
}

// Equality test with a string pointer to
// compare with.
bool QString::IsEqual( LPCTSTR pszSource ) const
{
    // Compare the two strings
    if ( m_pszString && pszSource && _tcscmp( m_pszString, pszSource ) == 0 )
        return true;

    return false;
}

// Return the character at "nIndex".
TCHAR QString::GetAt( int nIndex ) const
{
    ASSERT( nIndex >= 0 && nIndex < GetLength() ); // Stay in range.
    ASSERT( m_pszString );

    // Return the character.
    return m_pszString[ nIndex ];
}

// Return the character reference at "nIndex".
TCHAR & QString::GetAt( int nIndex )
{
    ASSERT( nIndex >= 0 && nIndex < GetLength() ); // Stay in range.
    ASSERT( m_pszString );

    // Return character reference.
    return ( TCHAR & )m_pszString[ nIndex ];
}

// Replace the character at "nIndex".
void QString::SetAt( int nIndex, TCHAR ch )
{
    ASSERT( nIndex >= 0 && nIndex < GetLength() ); // Stay in range.

    // Do not modify referenced data!
    CopyBeforeWrite();

    // Set the character.
    if ( m_pszString )
        m_pszString[ nIndex ] = ch;
}

// Compare this object with another string.
// <0 This object is smaller.
//  0 This object matches the string.
// >0 This object is larger.
int QString::Compare( LPCTSTR pszString ) const
{
    ASSERT( pszString ); // Must be valid.
    ASSERT( m_pszString ); // Can't compare with a nullptr string.

    // Return result.
    return _tcscmp( m_pszString, pszString );
}

// Compare this object with another string (no case).
// <0 This object is smaller.
//  0 This object matches the string.
// >0 This object is larger.
int QString::CompareNoCase( LPCTSTR pszString ) const
{
    ASSERT( pszString ); // Must be valid.
    ASSERT( m_pszString ); // Can't compare with a nullptr string.

    // Return result.
    return _tcsicmp( m_pszString, pszString );
}

int QString::NatCompare( LPCTSTR pszString ) const
{
    ASSERT( pszString ); // Must be valid.
    ASSERT( m_pszString ); // Can't compare with a nullptr string.

    // Return result.
    return Natcmp( m_pszString, pszString );
}
//#include<shlwapi.h >
int QString::NatCompareNoCase( LPCTSTR pszString ) const
{
    ASSERT( pszString ); // Must be valid.
    ASSERT( m_pszString ); // Can't compare with a nullptr string.


    //return StrCmpLogicalW(m_pszString, pszString );

    // Return result.
    return Naticmp( m_pszString, pszString );
}

// Compare this object with another string.
// Uses locale specific information.
// <0 This object is smaller.
//  0 This object matches the string.
// >0 This object is larger.
int QString::Collate( LPCTSTR pszString ) const
{
    ASSERT( pszString ); // Must be valid.
    ASSERT( m_pszString ); // Can't compare with a nullptr string.

    // Return result.
    return _tcscoll( m_pszString, pszString );
}

// Compare this object with another string.
// Uses locale specific information.
// <0 This object is smaller.
//  0 This object matches the string.
// >0 This object is larger.
int QString::CollateNoCase( LPCTSTR pszString ) const
{
    ASSERT( pszString ); // Must be valid.
    ASSERT( m_pszString ); // Can't compare with a nullptr string.

    // Return result.
    return _tcsicoll( m_pszString, pszString );
}

// Trims leading and trailing spaces from the
// contents.
QString & QString::Trim()
{
    // Anything to trim?
    if ( m_pszString )
    {
        // First remove the trailing spaces.
        int nPos = GetLength() - 1;

        while ( _istspace( m_pszString[ nPos ] ) ) nPos--;

        // Anything stripped?
        if ( nPos < GetLength() - 1 )
            SetStringLength( nPos + 1 );

        // Now count the leading spaces.
        nPos = 0;

        while ( _istspace( m_pszString[ nPos ] ) ) nPos++;

        // Anything to strip?
        if ( nPos )
        {
            // Move remaining characters in the buffer
            // and adjust the string length to match.
            memmove( &m_pszString[ 0 ], &m_pszString[ nPos ], ( GetLength() - nPos ) * sizeof( TCHAR ) );
            SetStringLength( GetLength() - nPos );
        }
    }

    return *this;
}

void QString::TrimLeft( TCHAR chTarget )
{
    // Anything to trim?
    if ( m_pszString )
    {

        // Now count the leading spaces.
        int nPos = 0;

        while ( m_pszString[ nPos ] == chTarget ) nPos++;

        // Anything to strip?
        if ( nPos )
        {
            // Move remaining characters in the buffer
            // and adjust the string length to match.
            memmove( &m_pszString[ 0 ], &m_pszString[ nPos ], ( GetLength() - nPos ) * sizeof( TCHAR ) );
            SetStringLength( GetLength() - nPos );
        }
    }
}

void QString::TrimRight( TCHAR chTarget )
{
    // Anything to trim?
    if ( m_pszString )
    {
        // First remove the trailing spaces.
        int nPos = GetLength() - 1;

        while ( m_pszString[ nPos ] == chTarget ) nPos--;

        // Anything stipped?
        if ( nPos < GetLength() - 1 )
            SetStringLength( nPos + 1 );
    }
}

void QString::AddBackslash( )
{

    // Add a backslash to the string if not yet present.


    if ( IsEmpty() )
    {
        operator +=(  QDIRDELIMITER ) ;
        return;
    }

    int pos = GetLength() - 1;

    if ( m_pszString[ pos ]  !=  QDIRDELIMITER )
        operator +=(  QDIRDELIMITER );


}
void QString::RemoveBackslash()
{
    ///adaos
    if ( IsEmpty() ) return;

    int pos = GetLength() - 1;

    if ( GetAt( pos ) == QDIRDELIMITER ||  GetAt( pos ) == QSLASH )
        Delete( pos );
}

bool QString::IsSeparator( TCHAR c )
{
    return ( c == QDIRDELIMITER || c == QSLASH );
}
void QString::RemoveSeparatorsLeft()
{
    // Anything to trim?
    if ( m_pszString )
    {

        // Now count the leading spaces.
        int nPos = 0;

        while ( m_pszString[ nPos ] == QDIRDELIMITER  || m_pszString[ nPos ] ==  QSLASH  ) nPos++;

        // Anything to strip?
        if ( nPos )
        {
            // Move remaining characters in the buffer
            // and adjust the string length to match.
            memmove( &m_pszString[ 0 ], &m_pszString[ nPos ], ( GetLength() - nPos ) * sizeof( TCHAR ) );
            SetStringLength( GetLength() - nPos );
        }
    }
}
void QString::RemoveSeparatorsRight(   )
{
    // Anything to trim?
    if ( m_pszString )
    {

        // First remove the trailing spaces.
        int nPos = GetLength() - 1;

        while ( m_pszString[ nPos ] == QDIRDELIMITER  || m_pszString[ nPos ] ==  QSLASH ) nPos--;

        // Anything stipped?
        if ( nPos < GetLength() - 1 )
            SetStringLength( nPos + 1 );
    }
}


// Extracts "nCount" characters from the left of the
// string and places them in a new object.
QString QString::Left( int nCount ) const
{
    if ( nCount > GetLength() )
        nCount = GetLength();


    ASSERT( nCount <= GetLength() ); // Can't extract more than there is.
    ASSERT( m_pszString ); // Can't extract from a nullptr string.

    // Create an object.
    QString	csTemp;

    // Allocate a buffer in it which will hold
    // the extracted part.
    csTemp.AllocateBuffer( nCount );

    // Copy the string.
    _tcsncpy( csTemp.m_pszString, m_pszString, nCount );

    // Return the new object.
    return csTemp;
}

// Extracts "nCount" characters from offset "nIndex" of the
// string and places them in a new object.
QString QString::Mid( int nIndex, int nCount /* == -1 */ ) const
{
    ASSERT( nIndex >= 0 && nIndex <= GetLength() ); // Make sure we are in range.
    ASSERT( m_pszString ); // Can't extract from a nullptr string.

    // Create an object.
    QString	csTemp;
    int		nNumChars = nCount == -1 ? GetLength() - nIndex : nCount;
    ASSERT( nNumChars + nIndex <= GetLength() ); // Extracting to much?

    // Allocate a buffer in it which will hold
    // the extracted part.
    csTemp.AllocateBuffer( nNumChars );

    // Copy the string.
    _tcsncpy( csTemp.m_pszString, &m_pszString[ nIndex ], nNumChars );

    // Return the new object.
    return csTemp;
}

// Extracts "nCount" characters from the right of the
// string and places them in a new object.
QString QString::Right( int nCount ) const
{
    ASSERT( nCount <= GetLength() ); // Can't extract more than there is.
    ASSERT( m_pszString ); // Can't extract from a nullptr string.

    // Create an object.
    QString	csTemp;

    // Allocate a buffer in it which will hold
    // the extracted part.
    csTemp.AllocateBuffer( nCount );

    // Copy the string.
    _tcsncpy( csTemp.m_pszString, &m_pszString[ GetLength() - nCount ], nCount );

    // Return the new object.
    return csTemp;
}

// Convert the contents to upper case.
void QString::UpperCase()
{
    // Do not modify referenced data!
    CopyBeforeWrite();

    // Convert casing.
    if ( m_pszString )
    {
        // Iterate the contents.
        for ( int i = 0; i < GetLength(); i++ )
            // Convert the character.
            m_pszString[ i ] = ( TCHAR )_totupper( m_pszString[ i ] );
    }
}

// Convert the contents to lower case.
void QString::LowerCase()
{
    // Do not modify referenced data!
    CopyBeforeWrite();

    // Convert casing.
    if ( m_pszString )
    {
        // Iterate the contents.
        for ( int i = 0; i < GetLength(); i++ )
            // Convert the chracter.
            m_pszString[ i ] = ( TCHAR )_totlower( m_pszString[ i ] );
    }
}

// Convert the contents to title case.
void QString::TitleCase()
{
    // Do not modify referenced data!
    CopyBeforeWrite();

    // Convert casing.
    if ( m_pszString )
    {
        // Iterate the contents.
        for ( int i = 0; i < GetLength(); i++ )

            // Convert the chracter.
            if (  ( i == 0 ) ||  ( i > 0 &&  m_pszString[i - 1] == _T( ' ' ) ) )
                m_pszString[ i ] = ( TCHAR )_totupper( m_pszString[ i ] );
    }
}
// Swap the contents to lower case.
void QString::SwapCase()
{
    // Do not modify referenced data!
    CopyBeforeWrite();

    // Convert casing.
    if ( m_pszString )
    {
        // Iterate the contents.
        for ( int i = 0; i < GetLength(); i++ )
        {
            // Swap the letter casing.
            if (	  _istupper( m_pszString[ i ] ) ) m_pszString[ i ] = ( TCHAR )_totlower( m_pszString[ i ] );
            else if ( _istlower( m_pszString[ i ] ) ) m_pszString[ i ] = ( TCHAR )_totupper( m_pszString[ i ] );
        }
    }
}

// Replace all instances of "chOld" with
// "chNew".
int QString::Replace( TCHAR chOld, TCHAR chNew )
{
    ASSERT( chOld != _T( '\0' ) && chNew != _T( '\0' ) ); // No 0 characters.

    // Are the characters different?
    if ( chOld == chNew )
        // No. Simply return 0;
        return 0;

    // Do not modify referenced data!
    CopyBeforeWrite();

    // Initialize replacement counter.
    int	nCount = 0;

    // Iterate characters.
    for ( int i = 0; i < GetLength(); i++ )
    {
        // Match?
        if ( m_pszString[ i ] == chOld )
        {
            // Replace it and increase the replacement
            // counter.
            m_pszString[ i ] = chNew;
            nCount++;
        }
    }

    // Return the replacement counter.
    return nCount;
}

// Remove all instances of "ch" from
// the string
int QString::Remove( TCHAR ch )
{
    ASSERT( ch != _T( '\0' ) ); // No 0 characters.

    // Do not modify referenced data!
    CopyBeforeWrite();

    // Initialize removement counter.
    int	nCount = 0;

    // Iterate characters.
    for ( int i = 0; i < GetLength(); i++ )
    {
        int nLength = GetLength();

        // Match?
        if ( m_pszString[ i ] == ch )
        {
            // Remove the character by moving all characters
            // right of it one place to the left.
            memmove( ( void * )&m_pszString[ i ], ( void * )&m_pszString[ i + 1 ], ( nLength - i ) * sizeof( TCHAR ) );
            SetStringLength( nLength - 1 );
            i--;
            nCount++;
        }
    }

    // Return the replacement counter.
    return nCount;
}

// Insert a character at the given index.
int QString::Insert( int nIndex, TCHAR ch )
{
    ASSERT( nIndex >= 0 && nIndex <= GetLength() ); // Make sure the index is valid.
    ASSERT( ch != _T( '\0' ) ); // No 0 characters.

    // Do we have contents?
    if ( m_pszString == nullptr )
        // No. Add the character.
        operator+=( ch );
    else
    {
        // Do not modify referenced data!
        CopyBeforeWrite();

        // How many characters must we move?
        int nChars = GetLength() - nIndex;

        // Make sure we have enough room to
        // add the character.
        AllocateBuffer( GetLength() + 1, TRUE );

        // Make room.
        memmove( ( void * )&m_pszString[ nIndex + 1 ], ( void * )&m_pszString[ nIndex ], nChars * sizeof( TCHAR ) );

        // Insert character.
        m_pszString[ nIndex ] = ch;
    }

    // Return the new length.
    return GetLength();
}

// Insert a string at the given index.
int QString::Insert( int nIndex, LPCTSTR pszString )
{
    ASSERT( nIndex >= 0 && nIndex <= GetLength() ); // Make sure the index is valid.
    ASSERT( pszString ); // No nullptr pointers.

    // Do we have contents?
    if ( m_pszString == nullptr )
        // No. Add the string.
        operator+=( pszString );
    else
    {
        // Do not modify referenced data!
        CopyBeforeWrite();

        // How many characters must we move?
        int nChars = GetLength() - nIndex;

        // Make sure we have enough room to
        // add the string.
        int nLength = ( int )_tcslen( pszString );
        AllocateBuffer( GetLength() + nLength, TRUE );

        // Make room.
        memmove( ( void * )&m_pszString[ nIndex + nLength ], ( void * )&m_pszString[ nIndex ], nChars * sizeof( TCHAR ) );

        // Insert string.
        memcpy( ( void * )&m_pszString[ nIndex ], ( void * )pszString, nLength * sizeof( TCHAR ) );
    }

    // Return the new length.
    return GetLength();
}

// Insert a string at the given index.
int QString::Insert( int nIndex, QString & csString )
{
    ASSERT( nIndex >= 0 && nIndex <= GetLength() ); // Make sure the index is valid.
    ASSERT( &csString != this ); // Do not insert into ourselves.

    // Do we have contents?
    if ( m_pszString == nullptr )
        // No. Add the string.
        operator+=( csString );
    else
        // Insert the string.
        Insert( nIndex, csString.m_pszString );

    // Return the new length.
    return GetLength();
}

// Delete one or more characters from the string.
int QString::Delete( int nIndex, int nCount /* = 1 */ )
{
    ASSERT( nIndex >= 0 && nIndex < GetLength() ); // Make sure the index is valid.
    ASSERT( nCount + nIndex <= GetLength() ); // Do not delete to much.

    // Do not modify referenced data!
    CopyBeforeWrite();

    // Move the contents right of the removed area.
    memmove( ( void * )&m_pszString[ nIndex ], ( void * )&m_pszString[ nIndex + nCount ], ( GetLength() - ( nIndex + nCount - 1 ) ) * sizeof( TCHAR ) );
    SetStringLength( GetLength() - nCount );

    // Return the new length.
    return GetLength();
}
int QString::Replace( const QString & oldString, const QString & newString )
{
    if ( oldString.IsEmpty() )
        return 0;

    if ( oldString == newString )
        return 0;

    int oldStringLength = oldString.GetLength();
    int newStringLength = newString.GetLength();
    int number  = 0;
    int pos  = 0;

    while ( pos < GetLength() )
    {
        pos = Find( oldString, pos );

        if ( pos < 0 )
            break;

        Delete( pos, oldStringLength );
        Insert( pos, newString );
        pos += newStringLength;
        number++;
    }

    return number;
}
// Find the first occurence of the character "ch"
// from "nIndex" on.
int QString::Find( TCHAR ch, int nIndex /* = 0 */ ) const
{
    ASSERT( nIndex >= 0 && nIndex < GetLength() ); // Make sure the index is valid.
    ASSERT( ch != _T( '\0' ) ); // No 0 characters.

    // Iterate string.
    for ( int i = nIndex; i < GetLength(); i++ )
    {
        // Character match?
        if ( m_pszString[ i ] == ch )
            return i;
    }

    return -1;
}

// Find the first occurence of the string "pszString"
// from "nIndex" on.
int QString::Find( LPCTSTR pszString, int nIndex /* = 0 */ ) const
{
    ASSERT( pszString ); // No nullptr pointers.
    ASSERT( nIndex >= 0 && nIndex <= GetLength() ); // Make sure the index is valid.

    // Iterate string.
    int nLength = ( int )_tcslen( pszString );

    for ( int i = nIndex; i <= ( int )( GetLength() - nLength ); i++ )
    {
        // Match?
        if ( _tcsncmp( &m_pszString[ i ], pszString, nLength ) == 0 )
            return i;
    }

    return -1;
}

int QString::FindNoCase( LPCTSTR pszString, int nIndex /* = 0 */ ) const
{
    ASSERT( pszString ); // No nullptr pointers.
    ASSERT( nIndex >= 0 && nIndex <= GetLength() ); // Make sure the index is valid.

    // Iterate string.
    int nLength = ( int )_tcslen( pszString );

    for ( int i = nIndex; i <= ( int )( GetLength() - nLength ); i++ )
    {
        // Match?
        if ( _tcsnicmp( &m_pszString[ i ], pszString, nLength ) == 0 )
            return i;
    }

    return -1;
}


// Find the first occurence of the character "ch"
// starting from the end of the string.
int QString::ReverseFind( TCHAR ch ) const
{
    ASSERT( ch != _T( '\0' ) ); // No 0 characters.

    // Iterate string.
    for ( int i = GetLength() - 1; i >= 0; i-- )
    {
        // Character match?
        if ( m_pszString[ i ] == ch )
            return i;
    }

    return -1;
}

// Find the first occurence of any of the characters in
// "pszCharSet" from "nIndex" on.
int QString::FindOneOf( LPCTSTR pszCharSet, int nIndex /* = 0 */ ) const
{
    ASSERT( nIndex >= 0 && nIndex <  GetLength() ); // Make sure the index is valid.
    ASSERT( pszCharSet ); // No nullptr pointers.

    // Iterate string.
    for ( int i = nIndex; i < GetLength(); i++ )
    {
        // Iterate character set.
        for ( int a = 0; a < ( int )_tcslen( pszCharSet ); a++ )
        {
            // Is it a match?
            if ( m_pszString[ i ] == pszCharSet[ a ] )
                return i;
        }
    }

    return -1;
}
int QString::ReverseFindOneOf( LPCTSTR pszCharSet ) const
{
    //ASSERT( nIndex >= 0 && nIndex < GetLength()); // Make sure the index is valid.
    ASSERT( pszCharSet ); // No nullptr pointers.

    // Iterate string.
    for ( int i = GetLength() - 1; i >= 0; i-- )
    {
        // Iterate character set.
        for ( int a = 0; a < ( int )_tcslen( pszCharSet ); a++ )
        {
            // Is it a match?
            if ( m_pszString[ i ] == pszCharSet[ a ] )
                return i;
        }
    }

    return -1;
}
// Format a system error.
void QString::FormatMessage( DWORD dwErrorID /* = 0 */ )
{
    // Format the error specified or the
    // current error.
    LPVOID	pMsgBuffer;
    DWORD dwSize = ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
                                    nullptr,
                                    dwErrorID ? dwErrorID : ::GetLastError(),
                                    MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
                                    ( LPTSTR )&pMsgBuffer,
                                    0,
                                    nullptr );

    // Do not modify referenced data!
    CopyBeforeWrite();

    // Error formatted OK?
    if ( dwSize )
    {
        // Allocate buffer.
        AllocateBuffer( dwSize );

        // Copy the result.
        _tcsncpy( m_pszString, ( LPCTSTR )pMsgBuffer, dwSize );

        // Free the result from the FormatMessage() API.
        ::LocalFree( pMsgBuffer );
    }
    else
        // Use a default output. Not exactly language independant...
        Format( _T( "Error %ld occured." ), dwErrorID ? dwErrorID : ::GetLastError() );
}

// Format a string.
void QString::Format( LPCTSTR pszFormatString, ... )
{
    ASSERT( pszFormatString ); // Must be valid...
    const int	sz = 16000;
    TCHAR		szBuffer[ sz ]; // 16Kbyte chars is max.
    int			nChars;

    // Do not modify referenced data!
    CopyBeforeWrite();

    // Format the output.
    va_list		args;
    va_start( args, pszFormatString );

    //nChars = ::vswprintf( szBuffer, pszFormatString, args);
    nChars = _vstprintf( szBuffer, sz-1, pszFormatString, args );


    va_end( args );

    // Allocate a buffer to fit.
    AllocateBuffer( nChars );

    // Copy contents.
    _tcscpy ( m_pszString,   szBuffer );
}

// Obtain a part of the string which is delimited by the
// specified character.
int QString::GetDelimitedPart( TCHAR ch, int nIndex, QString & str ) const
{
    ASSERT( ch != _T( '\0' ) ); // Must be a valid character.
    ASSERT( nIndex >= 0 ); // Index must be positive.

    // Empty?
    int nLength = GetLength();

    if ( nLength == 0 )
        return 0;

    // Get the string base.
    LPCTSTR psz = m_pszString;

    // Skip through to the index.
    int nCount = 0;

    for ( nCount = 0; nCount < nIndex; nCount++, psz = _tcsinc( psz ) );

    // Do not pass the end of the string.
    if ( nCount >= nLength )
        return 0;

    // Set the string to the remainder.
    str = psz;

    // Iterate string to find the next delimited
    // part.
    for ( ; nCount <= nLength; nCount++, psz = _tcsinc( psz ) )
    {
        // Is it the delimiter or a 0-character?
        if ( *psz == ch || *psz == _T( '\0' ) )
        {
            // Truncate the string.
            str.SetStringLength( nCount - nIndex );

            // Free the extra memory.
            //str.FreeExtra();

            // Return the index of the next entry.
            return nCount + 1;
        }
    }

    return 0;
}

// Load a string from the resources.
bool QString::LoadString( UINT uID )
{
    // First we try 256 character buffer from
    // the stack.
    TCHAR	szBuffer[ 256 ];
    int	nSize = 256;

    // Do not modify referenced data!
    CopyBeforeWrite();

    // Load the string. When the number of loaded characters
    // returned exactly equals the buffer size minus one we
    // can assume that LoadString() trunctated the string.
    int nChars = ::LoadString( GetModuleHandle( 0 ), uID, szBuffer, nSize );

    if ( nChars == nSize - 1 )
    {
        do
        {
            // Increase buffer size until we found
            // a size which will hold the string.
            nSize += 256;

            // Allocate buffer.
            AllocateBuffer( nSize );

            // Load the string.
            nChars = ::LoadString( GetModuleHandle( 0 ), uID, m_pszString, nSize );

        }
        while ( nChars == nSize - 1 );

    }
    else
    {
        // Allocate buffer and copy the contents of
        // the loaded string.
        AllocateBuffer( nChars );
        _tcscpy( m_pszString, szBuffer );
    }

    // Return success/failure.
    return ( bool )( nChars > 0 );
}

// Assignment operator.
const QString & QString::operator=( const QString & csSource )
{
    ASSERT( &csSource != this ); // We can't assign us to ourself.

    // Release current data.
    Release();

    // Set the source buffer in this object.
    m_pszString = csSource.m_pszString;

    // If the source was valid we add a reference to it.
    if ( m_pszString ) GetBuf()->AddRef();

    return *this;
}

// Assignment operator.
const QString & QString::operator=( LPCTSTR pszSource )
{
    ASSERT( pszSource ); // We can't assign to a nullptr pointer.

    // If the hi-order word of "pszSource" is 0
    // we load the string from the resources.
    if ( HIWORD( pszSource ) == 0 )
    {
        // Load the string.
        LoadString( LOWORD( pszSource ) );
        return *this;
    }

    // Do not modify referenced data!
    CopyBeforeWrite();

    // Allocate a new buffer.
    AllocateBuffer( ( int )_tcslen( pszSource )  );

    // Copy the contents of the source to this
    // object.
    _tcscpy( m_pszString, pszSource );
    return *this;
}

// Assignment operator.
const QString & QString::operator=( TCHAR ch )
{
    ASSERT( ch != _T( '\0' ) ); // We can't add a 0 character.

    // Do not modify referenced data!
    CopyBeforeWrite();

    // Allocate a new buffer.
    AllocateBuffer( 2 );

    // Copy the character.
    m_pszString[ 0 ] = ch;
    return *this;
}



// Assignment operator.
#ifndef _UNICODE
const QString & QString::operator=( LPCWSTR pszSource )
{
    ASSERT( pszSource ); // We can't assign to a nullptr pointer.

    // Do not modify referenced data!
    CopyBeforeWrite();

    // Allocate a new buffer.
    int nLength = ( int )wcslen( pszSource );
    AllocateBuffer( nLength );

    // Copy the string.
    wcstombs( m_pszString, pszSource, nLength * sizeof( TCHAR ) );
    return *this;
}
#else
const QString & QString::operator=( LPCSTR pszSource )
{
    ASSERT( pszSource ); // We can't assign to a nullptr pointer.

    // Do not modify referenced data!
    CopyBeforeWrite();

    // Allocate a new buffer.
    size_t nLength = strlen( pszSource );
    AllocateBuffer( ( int )nLength );

    // Copy the string.
    mbstowcs( m_pszString, pszSource, nLength );
    return *this;
}
#endif // _UNICODE


// Addition operator.
const QString & QString::operator+=( const QString & csSource )
{
    ASSERT( &csSource != this ); // We can't add us to ourself.

    ///alex
    if ( csSource.IsEmpty() )
        return *this;

    return operator+=( csSource.m_pszString );
}

// Addition operator.
const QString & QString::operator+=( LPCTSTR pszSource )
{
    ASSERT( pszSource ); // We can't add a nullptr pointer.
    size_t nlen = _tcslen( pszSource );

    if ( !nlen )
        return *this;

    // Do not modify referenced data!
    CopyBeforeWrite();


    int len = GetLength();
    // Allocate a new buffer copying the current
    // contents.
    size_t sz = len + nlen;
    AllocateBuffer( int( sz ), true );

    // Append string.
    ///*** aici trebuie strcpy daca sirul initial era vid
    ///*** si strcat daca nu era vid


    if ( len )
        _tcscat_s(  m_pszString , sz + 1 , pszSource );
    else
        _tcscpy_s(  m_pszString , sz + 1 , pszSource );

    return *this;
}

// Addition operator.
const QString & QString::operator+=( TCHAR ch )
{
    ASSERT( ch != _T( '\0' ) ); // We can't assign to 0 character.

    TCHAR   str[] = {ch, 0};

    return operator+=( str );
}

#ifndef _UNICODE
// Addition operator.
const QString & QString::operator+=( LPCWSTR pszSource )
{
    ASSERT( pszSource ); // We can't add a nullptr pointer.

    // Do not modify referenced data!
    CopyBeforeWrite();

    // Allocate a new buffer copying the current
    // contents.
    int nLength = GetLength(), nNew = ( int )wcslen( pszSource );
    AllocateBuffer( nLength + nNew, TRUE );

    // Append string.
    wcstombs( &m_pszString[ nLength ], pszSource, ( nNew * sizeof( TCHAR ) ) );
    return *this;
}
#else
// Addition operator.
const QString & QString::operator+=( LPCSTR pszSource )
{
    ASSERT( pszSource ); // We can't add a nullptr pointer.

    // Do not modify referenced data!
    CopyBeforeWrite();

    // Allocate a new buffer copying the current
    // contents.
    size_t nLength = GetLength(), nNew = strlen( pszSource );
    AllocateBuffer( int( nLength + nNew ), TRUE );

    // Append string.
    size_t sz;
    mbstowcs_s( &sz,  &m_pszString[ nLength ], nLength + nNew,  pszSource, nNew );
    return *this;
}
#endif


// Comparison operator.
bool QString::operator>=( const QString & csSource ) const
{
    ASSERT( m_pszString );
    ASSERT( csSource.m_pszString );
    return ( bool )( _tcscmp( m_pszString, csSource ) >= 0 );
}

// Comparison operator.
bool QString::operator>=( LPCTSTR pszSource ) const
{
    ASSERT( m_pszString );
    ASSERT( pszSource );
    return ( bool )( _tcscmp( m_pszString, pszSource ) >= 0 );
}

// Comparison operator.
bool QString::operator>( const QString & csSource ) const
{
    ASSERT( m_pszString );
    ASSERT( csSource.m_pszString );
    return ( bool )( _tcscmp( m_pszString, csSource ) > 0 );
}

// Comparison operator.
bool QString::operator>( LPCTSTR pszSource ) const
{
    ASSERT( m_pszString );
    ASSERT( pszSource );
    return ( bool )( _tcscmp( m_pszString, pszSource ) > 0 );
}

// Comparison operator.
bool QString::operator<( const QString & csSource ) const
{
    ASSERT( m_pszString );
    ASSERT( csSource.m_pszString );
    return ( bool )( _tcscmp( m_pszString, csSource ) < 0 );
}

// Comparison operator.
bool QString::operator<( LPCTSTR pszSource ) const
{
    ASSERT( m_pszString );
    ASSERT( pszSource );
    return ( bool )( _tcscmp( m_pszString, pszSource ) < 0 );
}

// Comparison operator.
bool QString::operator<=( const QString & csSource ) const
{
    ASSERT( m_pszString );
    ASSERT( csSource.m_pszString );
    return ( bool )( _tcscmp( m_pszString, csSource ) <= 0 );
}

// Comparison operator.
bool QString::operator<=( LPCTSTR pszSource ) const
{
    ASSERT( m_pszString );
    ASSERT( pszSource );
    return ( BOOL )( _tcscmp( m_pszString, pszSource ) <= 0 );
}

// Get a buffer (non-referenced).
LPTSTR QString::GetBuffer( int nChars )
{
    // Release current buffer.
    Release();

    // Allocate new buffer.
    AllocateBuffer( nChars );

    // Return pointer to it.
    return m_pszString;
}

// Allocate a new memory buffer.
void QString::AllocateBuffer( int nChars, bool bCopy /* = FALSE */ )
{
    ASSERT( nChars >= 0 );

    // Preset to nullptr.
    QStringBuffer * pNew = nullptr;

    // Do we already have a buffer?
    if ( m_pszString )
    {
        // Is the available size enough to hold
        // the requested size?
        if ( nChars > ( GetBuf()->GetMax() - 1 ) )
            // We need to allocate a new buffer.
            pNew = QStringBuffer::AllocBuffer( nChars );
    }
    else
        // We always need to allocate a new buffer
        // when there is no current buffer.
        pNew = QStringBuffer::AllocBuffer( nChars );

    // Have we allocated a new buffer?
    if ( pNew )
    {
        // Copy the old contents?
        if ( bCopy && m_pszString )
            memcpy( pNew->GetString(), m_pszString, GetBuf()->GetMax() * sizeof( TCHAR ) );

        // Free the old buffer.
        Release();

        // Setup the new buffer.
        m_pszString = pNew->GetString();
    }
    else
        // Setup the new length.
        GetBuf()->SetLength( nChars, true );
}

// Make sure we do not modify referenced data.
void QString::CopyBeforeWrite()
{

    // Do we have a string?
    if ( m_pszString )
    {
        // Is the current contents a referenced string?
        if ( GetBuf()->IsShared() )
        {
            // Create a new string buffer which has enough room to hold
            // the original string.
            QStringBuffer * pNew = QStringBuffer::AllocBuffer( GetBuf()->GetMax() );

            // Setup it's length.
            pNew->SetLength( GetBuf()->GetLength() );

            // Copy the contents of the original to the new buffer.
            memcpy( pNew->GetString(), m_pszString, GetBuf()->GetLength() * sizeof( TCHAR ) );

            // Release the reference.
            GetBuf()->Release();

            // Setup the new pointer.
            m_pszString = pNew->GetString();
        }
    }
}

// Release the string buffer and, if the reference
// count is below 1 free the memory.
void QString::Release()
{
    // Do we have a string?
    if ( m_pszString )
    {
        // Release our reference.
        if ( GetBuf()->Release() <= 0 )
        {
            // Free the memory and clear the pointer.
            QStringBuffer::FreeBuffer( GetBuf() );
            m_pszString = nullptr;
        }
    }
}

//
//CHAR *  QString::GetAscii()
//{
//	// Anything to convert?
//	if ( m_pszString )
//	{
//
//
//		int len = GetLength() ;
//			// Allocate a buffer to hold the conversion.
//			CHAR * pszConverted = new CHAR[ 2*len ];
//
//			size_t sz = 0;
//			// Do the actual conversion.
//			wcstombs_s( &sz, pszConverted, 2*len,  m_pszString, len );
//			return pszConverted;
//
//	}
//
//	return nullptr;
//}


QString QString::digestToHex( const unsigned char * bytes, int n )
{
    static const TCHAR digits[] = L"0123456789abcdef";
    QString result;

//	result.reserve(bytes.size()*2);
    for ( int i = 0; i < n; i++ )
    {
        unsigned char c = bytes[i];
        result += digits[( c >> 4 ) & 0x0F];
        result += digits[c & 0x0F];
    }

    return result;
}



int QString::compare_right( LPCTSTR  a, LPCTSTR  b )
{
    int bias = 0;

    /* The longest run of digits wins.  That aside, the greatest
    value wins, but we can't know that it will until we've scanned
    both numbers to know that they have the same magnitude, so we
    remember it in BIAS. */
    while ( true )
    {

        if ( ! _istdigit( *a )  &&  ! _istdigit( *b ) )
            return bias;

        if ( !_istdigit( *a ) )
            return -1;

        if ( !_istdigit( *b ) )
            return +1;

        if ( *a < *b )
        {
            if ( 0 == bias )
                bias = -1;
        }
        else if ( *a > *b )
        {
            if ( 0 == bias )
                bias = +1;
        }
        else if ( !*a  &&  !*b )
            return bias;

        a++;
        b++;

    }

    return 0;
}


int QString::compare_left( LPCTSTR a, LPCTSTR  b )
{
    /// Compare two left-aligned numbers: the first to have a different value wins.
    while ( true )
    {

        if ( ! _istdigit( *a )  &&  !_istdigit( *b ) )
            return 0;

        if ( !_istdigit( *a ) )
            return -1;

        if ( !_istdigit( *b ) )
            return +1;

        if ( *a < *b )
            return -1;

        if ( *a > *b )
            return +1;

        a++;
        b++;
    }

    return 0;
}


int QString::strnatcmp0( LPCTSTR  a, LPCTSTR  b, bool icase )
{
    int		ai = 0;
    int		bi = 0;
    bool	fractional;
    int		result;

    ASSERT( a );
    ASSERT( b );

    while ( true )
    {
        TCHAR  ca = a[ai];
        TCHAR  cb = b[bi];

        /* skip over leading spaces or zeros */
        while ( _istspace( ca ) ) 	ca = a[++ai];

        while ( _istspace( cb ) ) 	cb = b[++bi];

        /* process run of digits */
        if ( _istdigit( ca )  &&  _istdigit( cb ) )
        {
            fractional = ( ca == _T( '0' ) || cb == _T( '0' ) );

            if ( fractional )
            {
                if ( ( result = compare_left( a + ai, b + bi ) ) != 0 )
                    return result;
            }
            else
            {
                if ( ( result = compare_right( a + ai, b + bi ) ) != 0 )
                    return result;
            }
        }

        if ( !ca && !cb )
        {
            /* The strings compare the same.  Perhaps the caller
            		will want to call strcmp to break the tie. */
            return 0;
        }

        if ( icase )
        {
            ca = toupper( ca );
            cb = toupper( cb );
        }

        if ( ca < cb )
            return -1;

        if ( ca > cb )
            return +1;

        ++ai;
        ++bi;
    }
}



int QString::Natcmp( LPCTSTR  a, LPCTSTR b )
{
    return strnatcmp0( a, b, false );
}



/* Compare, recognizing numeric string and ignoring case. */
int QString::Naticmp( LPCTSTR  a, LPCTSTR b )
{
    return strnatcmp0( a, b, true );
}

